﻿/* 
 * Copyright (c) 2011-12 Andrey Bulygin
 * 
 * This file is part of Interceptor.
 * Interceptor is free software: you can redistribute it and/or modify it under the terms of the GNU 
 * Library General Public License as published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * Interceptor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 
 * the GNU Library General Public License for more details. You should have received a copy of the GNU 
 * Library General Public License along with Interceptor. If not, write to the Free Software Foundation, Inc., 59 
 * Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Interceptor.Core.Objects;

namespace Interceptor.Core
{
	internal class AttributeFilterValidator
	{
		static Dictionary<ErrorCode, string> _errorDescr = new Dictionary<ErrorCode,string>();
		static AttributeFilterValidator()
		{
			_errorDescr = new Dictionary<ErrorCode, string>();

			_errorDescr.Add(ErrorCode.FilterMethodIsStatic, "Attribute filter method couldn't be instance method. It should be static.");
			_errorDescr.Add(ErrorCode.FilterMethodReturnType, "Attribute filter method should return only bool result. True if this attribute instance does well for method. False otherwise.");
			_errorDescr.Add(ErrorCode.FilterMethodParametersCount, "Attribute filter method should accept only one parameter of Attribute type or array of Attribute types.");
			_errorDescr.Add(ErrorCode.FilterMethodFirstParameterIsNotAttrubute, "The first parameters of attribute filter method should be of type Attribute or array of Attribute.");
		}
		private AttributeFilterValidator()
		{
		}

		private ValidationError CreateError(MethodInfo method, ErrorCode errorCode)
		{
			return new ValidationError(GetInterceptorDefinition(method), errorCode, _errorDescr[errorCode]);
		}
		private string GetInterceptorDefinition(MethodInfo itcMethod)
		{
			return String.Format("{0}({1}): {2}", itcMethod.Name, String.Join(", ", itcMethod.GetParameters().Select(x => x.ParameterType.Name)), itcMethod.ReturnType.Name);
		}
		public static ValidationError[] Validate(MethodInfo filterMethod)
		{
			return new AttributeFilterValidator().ValidateFilter(filterMethod);
		}

		private ValidationError[] ValidateFilter(MethodInfo filterMethod)
		{
			var errors = new List<ValidationError>();
			if (!filterMethod.IsStatic)
				errors.Add(CreateError(filterMethod,ErrorCode.FilterMethodIsStatic));
			if (filterMethod.ReturnType != typeof(bool))
				errors.Add(CreateError(filterMethod, ErrorCode.FilterMethodReturnType));

			var parameters = filterMethod.GetParameters();
			if (parameters.Length!=1)
				errors.Add(CreateError(filterMethod, ErrorCode.FilterMethodParametersCount));
			else
			{
				Type parameterType = parameters[0].ParameterType.IsArray
						? parameters[0].ParameterType.GetElementType()
						: parameters[0].ParameterType;

				if (!parameterType.IsSubclassOf(typeof(Attribute)))
					errors.Add(CreateError(filterMethod, ErrorCode.FilterMethodFirstParameterIsNotAttrubute));
			}
			return errors.ToArray();
		}
	}
}
